/**
 * 
 */
package com.kovell.profileo.servicebean;

import javax.persistence.EntityExistsException;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.persistence.TransactionRequiredException;

import com.kovell.profileo.entity.BaseEntity;
import com.kovell.profileo.exception.EntityException;

/**
 * @author SOSSERES
 *
 */
public class BaseEntityService {
	
	@PersistenceContext(unitName="profileo_PU")
	private EntityManager em;

	/**
	 * 
	 */
	public BaseEntityService() {
	}
	
	public EntityManager getEntityManager(){
		return em;
	}
	
	public void close() throws EntityException{
		if(em == null || !em.isOpen()){
			System.out.println("EntityManager: is closed.");
			return;
		}
			
		try{			
			em.close();			
		}catch(IllegalStateException e){
			System.out.println("EntityManager is fail to close.");
			throw new EntityException(e);
		}
	}

	public <T extends BaseEntity> void create(T t) throws EntityException {
		try{
			em.persist(t);
			em.flush();
			
		}catch(EntityExistsException e){			
//			 if the entity already exists. (The EntityExistsException may be thrown when the persist 
//			 operation is invoked, or the EntityExistsException or 
//			 another PersistenceException may be thrown at flush or commit time.)			 
			throw new EntityException(e);
		}catch(IllegalStateException e){	// if this EntityManager has been closed
			throw new EntityException(e);
		}catch(IllegalArgumentException e){	// if instance is not an entity or is a rgetEntityManager()oved entity 
			throw new EntityException(e);
		}catch(TransactionRequiredException e){	//  if invoked on a container-managed entity manager of type PersistenceContextType.TRANSACTION and there is no transaction.
			throw new EntityException(e);
		}catch(PersistenceException e){	// if the flush fails
			
			throw new EntityException(e); 
		}
	}
	
	public <T extends BaseEntity> void delete(T t) throws EntityException {
		try{
			em.remove(t);
			em.flush();
			
//		}catch(IllegalStateException e){
//			throw new EntityException("IllegalStateException", e);
		}catch(IllegalArgumentException e){
			throw new EntityException(e);
		}catch (TransactionRequiredException e){
			throw new EntityException(e);
		}catch(PersistenceException e){
			throw new EntityException(e);
		}
	}

	public <T extends BaseEntity> void update(T t) throws EntityException {
		try{
			em.merge(t);
			em.flush();			
		}catch(IllegalArgumentException e){
			throw new EntityException(e);
//		}catch(IllegalStateException e){
//			throw new EntityException(e);
		}catch(TransactionRequiredException e){
			throw new EntityException(e);
		}catch(PersistenceException e){
			throw new EntityException(e);
		}
		
	}

	public <T> T find(Class<T> clazz, String id) throws EntityException {
		try{
			return em.find(clazz, id);
		}catch(IllegalArgumentException e){
			throw new EntityException(e);
		}catch(IllegalStateException e){
			throw new EntityException(e);
		}
	}
	
	public <T> T find(Class<T> clazz, String uniqueColumnName, Object value) throws EntityException{
		
		String sql = "SELECT x FROM " + clazz.getSimpleName() + " x WHERE x." + uniqueColumnName + " = :value";
		
		try{
			Query query = em.createQuery(sql).setParameter("value", value);
			return (T) query.getSingleResult();
		
		}catch(IllegalStateException e){
			throw new EntityException(e);
		}catch(IllegalArgumentException e){
			throw new EntityException(e);
		}catch(NonUniqueResultException e){
			throw new EntityException(e);
		}catch(NoResultException e){
			throw new EntityException(e);
		}
	}

}
